###########################################################################
#
#   Copyright 2010 American Public Media Group
#
#   This file is part of AIR2.
#
#   AIR2 is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   AIR2 is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################

package AIR2::Inquiry;
use strict;
use base qw(AIR2::DB);
use Carp;

__PACKAGE__->meta->setup(
    table => 'inquiry',

    columns => [
        inq_id   => { type => 'serial', not_null => 1 },
        inq_uuid => {
            type     => 'character',
            default  => '',
            length   => 12,
            not_null => 1
        },
        inq_title => {
            type     => 'varchar',
            length   => 128,
            not_null => 1
        },
        inq_ext_title => {
            type     => 'varchar',
            length   => 255,
            not_null => 1,
        },
        inq_expire_msg => { type => 'text',    length => 65555, },
        inq_desc       => { type => 'varchar', length => 255 },
        inq_type       => {
            type     => 'character',
            default  => 'F',
            length   => 1,
            not_null => 1
        },
        inq_status => {
            type     => 'character',
            default  => 'A',
            length   => 1,
            not_null => 1
        },
        inq_xid    => { type => 'integer' },
        inq_loc_id => {
            type     => 'integer',
            default  => 52,          # en_US
            not_null => 1
        },
        inq_public_flag => { type => 'integer', default => 1, not_null => 1 },
        inq_cre_user => { type => 'integer', not_null => 1 },
        inq_upd_user => { type => 'integer' },
        inq_cre_dtim => {
            type     => 'datetime',
            not_null => 1
        },
        inq_upd_dtim      => { type => 'datetime' },
        inq_expire_dtim   => { type => 'datetime' },
        inq_publish_dtim  => { type => 'datetime' },
        inq_deadline_dtim => { type => 'datetime' },
    ],

    primary_key_columns => ['inq_id'],

    unique_key => ['inq_uuid'],

    foreign_keys => [
        cre_user => {
            class       => 'AIR2::User',
            key_columns => { inq_cre_user => 'user_id' },
        },

        upd_user => {
            class       => 'AIR2::User',
            key_columns => { inq_upd_user => 'user_id' },
        },

        locale => {
            class       => 'AIR2::Locale',
            key_columns => { inq_loc_id => 'loc_id' },
        },
    ],

    relationships => [
        project_inquiries => {
            class      => 'AIR2::ProjectInquiry',
            column_map => { inq_id => 'pinq_inq_id' },
            type       => 'one to many',
        },

        projects => {
            map_class => 'AIR2::ProjectInquiry',
            map_from  => 'inquiry',
            map_to    => 'project',
            type      => 'many to many',
        },

        questions => {
            class      => 'AIR2::Question',
            column_map => { inq_id => 'ques_inq_id' },
            type       => 'one to many',
        },

        src_inquiries => {
            class      => 'AIR2::SrcInquiry',
            column_map => { inq_id => 'si_inq_id' },
            type       => 'one to many',
        },

        src_response_sets => {
            class      => 'AIR2::SrcResponseSet',
            column_map => { inq_id => 'srs_inq_id' },
            type       => 'one to many',
        },
    ],
);

sub tag_ref_type {'I'}

sub init_indexer {
    my $self = shift;
    return $self->SUPER::init_indexer(
        prune => {

        },
        max_depth        => 2,
        xml_root_element => 'inquiry',
        force_load       => 0,
        @_
    );
}

my @indexables = qw(
    questions
    src_inquiries
    project_inquiries
);

sub load_indexable_rels {
    my $self = shift;
    for my $rel (@indexables) {
        $self->$rel;
    }
    for my $pi ( @{ $self->project_inquiries } ) {
        $pi->project;
    }
}

sub get_title {
    my $self = shift;
    return $self->inq_ext_title || $self->inq_title;
}

=head2 as_xml( I<args> )

Returns Inquiry as XML string, suitable for indexing.

I<args> should contain a Rose::DBx::Object::Indexed::Indexer
object and other objects relevant to the XML structure.
See bin/inq2xml.pl for example usage.

=cut

sub as_xml {
    my $inq     = shift;
    my $args    = shift or croak "args required";
    my $debug   = delete $args->{debug} || 0;
    my $indexer = delete $args->{indexer}
        || $inq->init_indexer( debug => $debug, );
    my $base_dir = delete $args->{base_dir}
        || Path::Class::dir('no/such/dir');
    my $sources = delete $args->{sources}
        || AIR2::SearchUtils::get_source_org_matrix();

    $inq->load_indexable_rels;

    my $dmp = $indexer->serialize_object($inq);

    # we don't load the sources themselves but do reference their uuids
    # this is not strictly necessary because
    # the src_id is in the sources index too,
    # but as an exercise it's a good idea.
    for my $src ( @{ $dmp->{src_inquiries} } ) {
        my $sid = $src->{si_src_id};
        if ( !exists $sources->{$sid} ) {
            croak "No such src_id $sid in sources";
        }
        push @{ $dmp->{src_uuids} }, $sources->{$sid}->{uuid};
    }

    # TODO audit this
    # for authz we need the org_ids
    # that this inquiry is related to via its parent project(s).
    my @org_ids;
    my @org_names;
    my @org_uuids;
    my @authz;
    my @prj_uuid_titles;
    for my $prjinq ( @{ $inq->project_inquiries } ) {
        next if $prjinq->pinq_status ne 'A';
        push @org_ids,   @{ $prjinq->project->get_org_ids() };
        push @org_names, @{ $prjinq->project->get_org_names() };
        push @org_uuids, @{ $prjinq->project->get_org_uuids() };
        push @authz,     @{ $prjinq->project->get_authz() };
        push @prj_uuid_titles,
            join( ":",
            $prjinq->project->prj_uuid,
            $prjinq->project->prj_display_name ),
            ;
    }
    $dmp->{org_ids}         = \@org_ids;
    $dmp->{org_names}       = \@org_names;
    $dmp->{org_uuids}       = \@org_uuids;
    $dmp->{prj_uuid_titles} = \@prj_uuid_titles;

    my %response_sets;
    my $srsets = $inq->src_response_sets_iterator;
    while ( my $srs = $srsets->next ) {
        my $srs_id = $srs->srs_id;
        my $path   = AIR2::SearchUtils::xml_path_for( $srs_id,
            $base_dir->subdir( '..', 'responses' ) );

        $response_sets{$srs_id} = $path;
    }

    # virtual field for question sequence+value for display
    for my $q ( @{ $dmp->{questions} } ) {
        $q->{ques_seq_value}
            = join( ':', $q->{ques_dis_seq}, $q->{ques_value} );
    }

    $dmp->{tags}           = [ map { $_->get_name } @{ $inq->get_tags } ];
    $dmp->{author}         = $inq->get_cre_user->get_name;
    $dmp->{inq_uuid_title} = join( ':', $inq->inq_uuid, $inq->get_title );

    my $xml = $indexer->to_xml( $dmp, $inq );

    # hack in the authz string
    my $authz_str = join( ",", @authz );
    my $root = $indexer->xml_root_element;
    $xml =~ s,^<$root,<$root authz="$authz_str",;

    # to conserve processing time and disk space,
    # we use xinclude to virtually include records we have
    # serialized in other processes.
    $xml =~ s,<$root,<$root xmlns:xi="http://www.w3.org/2003/XInclude",;

    # add the xincludes for response sets
    my $xml_fragment = sprintf( "<response_sets count='%d'>",
        scalar( keys %response_sets ) );
    for my $srs_id ( sort keys %response_sets ) {
        $xml_fragment .= qq(<xi:include href="$response_sets{$srs_id}"/>);
    }
    $xml_fragment .= qq(</response_sets>);

    # close it
    $xml =~ s,</$root>,$xml_fragment</$root>,;

    return $xml;

}

1;

